
import unittest
import types

class TestDynamicProgram(unittest.TestCase):
    
    def test_type(self):
        """
        'is' can be used here, because during runtime, only one type object exists to represent a class of objects
        whether it is built-in type or user-defined type
        """
        int_type = type(5)
        self.assertTrue(int_type is int)
        self.assertTrue(int_type is types.IntType)
        
        # it seems that 'float' is just an alias of 'types.FloatType'
        self.assertTrue(float is types.FloatType)
        
        type_type = type(int_type)
        self.assertTrue(type_type is type)
        
    def test_isinstance(self):
        """
        this testcase shows that 'isinstance' can be passed multiple target types
        to achieve a OR effect
        """
        self.assertTrue(isinstance(5,(int,float)))
        self.assertTrue(isinstance(3.14,(int,float)))
        self.assertFalse(isinstance("cheka",(int,float)))
        
        
    def test_type_name(self):
        for type_name in ["int","float","long","str","complex"]:
            type_obj = eval(type_name)
            self.assertTrue(isinstance(type_obj,type))
            self.assertEqual(type_name,type_obj.__name__)
        
    def test_repr_eval(self):
        """
        repr and eval is a pair of reverse function
        
        repr : object --> string
        eval : string --> object
        """
        ori_value = 100
        repr_string = repr(ori_value)
        cpy_value = eval(repr_string)
        self.assertEqual(ori_value,cpy_value)
        
    def test_eval(self):
        self.assertEqual(100,eval("80 + 20"))
        # chekanote: what `` returns is still string, `` equivalent to repr, not eval
        # it returns not the result, but a string that can be executed
        self.assertEqual("100",`80 + 20`)
        
class TestAttributes(unittest.TestCase):
    """
    like Reflection in other languages, access properties of an object by name
    """
    class Helper(object):
        def __init__(self,initvalue = 10):
            self.member = initvalue
        
    def test_has_attr(self):
        obj = TestAttributes.Helper()
        self.assertTrue(hasattr(obj,"member"))
        self.assertFalse(hasattr(obj,"notexisted"))
        
    def test_get_attr(self):
        obj = TestAttributes.Helper(100)
        self.assertEqual(100,getattr(obj,"member"))
        
        obj.member = "cheka"
        self.assertEqual("cheka",getattr(obj,"member"))
        
        self.assertRaises(AttributeError,lambda:  getattr(obj,"noexisted"))
        
    def test_set_attr(self):
        # --------------- if the attribute exists, just replace old value with new value
        obj = TestAttributes.Helper()
        setattr(obj,"member","newvalue")
        self.assertEqual("newvalue",obj.member)
        
        # --------------- otherwise, create a new attribute
        self.assertFalse(hasattr(obj,"new_member"))
        setattr(obj,"new_member",99)
        self.assertEqual(99,obj.new_member)
        
    def test_vars(self):
        obj = TestAttributes.Helper()
        setattr(obj,"new_member",99)
        self.assertEqual({"new_member":99,"member":10},vars(obj))
        
        
if __name__ == "__main__":
    unittest.main()